package object

import (
	"reflect"
	"time"

	"gddgame.cc/galaxy/common/dsl/game"
	. "gddgame.cc/galaxy/common/dsl/game/base"
	. "gddgame.cc/galaxy/common/dsl/game/group"
	"gddgame.cc/galaxy/utils/orm"

	"gddgame.cc/galaxy/utils"
)

type ObjectData struct {
	// object不会修改，保持引用即可
	Objects []*SettingObject

	// 根据object属性划分
	ObjectMap   map[int]*SettingObject
	ObjectGroup map[int][]int

	ObjectInfoWithObject []*ObjectInfo

	ObjectGroupStat map[int][]string

	modelModel  *orm.Model
	objectModel *orm.Model

	//
	PowerObjectsRandom *utils.WeightRandom
	PowerObjects       []int
}

func GetObjectData(env *game.Environment, extendType reflect.Type, insideType reflect.Type, baseData *BaseData, groupData *GroupData) (*ObjectData, error) {
	var err error
	data := &ObjectData{}

	if data.modelModel, err = getModelData(env); err != nil {
		return nil, err
	}
	if data.objectModel, _, data.Objects, err = getObjectData(env, extendType, insideType); err != nil {
		return nil, err
	}

	objectProvider := &game.DataProvider{
		Name:     "object",
		Language: true,
		Array:    true,
		Get: func() (i interface{}, err error) {
			return data.ObjectInfoWithObject, nil
		},
	}
	env.RegisterData(objectProvider)
	// 划分Object分组
	data.ObjectMap = make(map[int]*SettingObject)
	data.ObjectGroup = make(map[int][]int)
	data.ObjectGroup[DefaultGroup] = make([]int, 0)
	data.ObjectGroupStat = make(map[int][]string)
	for k := range data.Objects {
		object := data.Objects[k]
		groupStats := make([]string, 0)
		groupStats = append(groupStats, object.MakeKey())
		prop := object
		for _, group := range prop.Group {
			g, ok := groupData.GroupMap[group]
			if !ok {
				continue
			}
			if g.StatKey != "" {
				groupStats = append(groupStats, g.StatKey)
			}
			if _, ok := data.ObjectGroup[group]; !ok {
				data.ObjectGroup[group] = make([]int, 0)
			}
			data.ObjectGroup[group] = append(data.ObjectGroup[group], prop.Id)
		}
		data.ObjectMap[prop.Id] = prop
		data.ObjectGroup[DefaultGroup] = append(data.ObjectGroup[DefaultGroup], prop.Id)
		data.ObjectGroupStat[prop.Id] = groupStats
	}

	data.ObjectInfoWithObject = make([]*ObjectInfo, len(data.Objects))
	for key := range data.Objects {
		object := data.Objects[key]
		base := baseData.Bases[object.BaseId]
		data.ObjectInfoWithObject[key] = NewObjectInfoFromObject(objectProvider, object, base, object.Ai)
	}

	data.PowerObjectsRandom = utils.NewWeightRandom()
	data.PowerObjects = []int{}
	for _, object := range data.Objects {
		if object.Category == PowerObjectCategory {
			data.PowerObjectsRandom.Add(object.Id, 0)
			data.PowerObjects = append(data.PowerObjects, object.Id)
		}
	}
	return data, err
}

func getModelData(env *game.Environment) (*orm.Model, error) {
	var err error

	model, err := env.GetModel(SettingObjectModelName)
	if err != nil {
		return nil, err
	}
	return model, nil
}
func getObjectData(env *game.Environment, extendType reflect.Type, insideType reflect.Type) (*orm.Model, []SettingObject, []*SettingObject, error) {
	var err error

	model, err := env.GetModel(SettingObjectName)
	if err != nil {
		return nil, nil, nil, err
	}
	var objects []SettingObject
	_, err = model.Query().Find(&objects)
	if err != nil {
		return nil, nil, nil, err
	}
	objectMap := make([]*SettingObject, len(objects))
	for k := range objects {
		if extendType != nil {
			objects[k].Extend = utils.ToType(objects[k].Extend, extendType)
		}
		if insideType != nil {
			objects[k].Inside = utils.ToType(objects[k].Inside, insideType)
		}
		objectMap[k] = &objects[k]
	}
	return model, objects, objectMap, nil
}

func (objectData *ObjectData) GetObject() []*ObjectInfo {
	return objectData.ObjectInfoWithObject
}

func (objectData *ObjectData) GetAllObject(updateTime *time.Time) ([]*ObjectInfo, error) {
	if updateTime != nil {
		objects := make([]*ObjectInfo, 0, 5)
		for _, object := range objectData.ObjectInfoWithObject {
			if object.HasUpdate(updateTime) {
				objects = append(objects, object)
			}
		}
		return objects, nil
	} else {
		return objectData.ObjectInfoWithObject, nil
	}
}
